#include "http.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Memory
{
    char *response; // 动态分配的缓冲区存储HTTP响应数据
    size_t size;    // 缓冲区大小
};

// CURL写数据的回调函数
static size_t write_callback(void *contents, size_t size, size_t nmemb, void *userp)
{
    size_t real_size = size * nmemb;             // 计算实际数据块大小
    struct Memory *mem = (struct Memory *)userp; // 类型转换，指向传入的缓冲区

    // 重新分配内存以存储新数据（当前大小 + 新数据块大小 + 1）
    char *ptr = realloc(mem->response, mem->size + real_size + 1);
    if (!ptr)
    {
        printf("Not enough memory (realloc returned NULL)\n");
        return 0; // 如果内存不足，返回0告知CURL停止操作
    }

    mem->response = ptr;                                      // 更新指针
    memcpy(&(mem->response[mem->size]), contents, real_size); // 将新数据拷贝到缓冲区末尾
    mem->size += real_size;                                   // 更新缓冲区大小
    mem->response[mem->size] = '\0';                          // 确保缓冲区以空字符结束
    return real_size;                                         // 返回实际写入的数据大小
}

/**
 * 发送HTTP GET请求
 * @param url 请求的URL
 * @return 成功返回响应内容，失败返回NULL
 */
char *http_get(const char *url)
{
    CURL *curl;
    CURLcode res;
    struct Memory chunk = {0}; // 初始化动态字符串结构

    chunk.response = malloc(1); // 初始化为最小大小，足以存储'\0'
    chunk.size = 0;             // 初始化大小为0

    curl = curl_easy_init(); // 初始化CURL会话
    if (curl)
    {
        curl_easy_setopt(curl, CURLOPT_URL, url);                      // 设置请求的URL
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback); // 设置写数据的回调函数
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);     // 设置写数据的用户参数

        res = curl_easy_perform(curl); // 执行请求
        if (res != CURLE_OK)
        { // 检查请求是否成功
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
            free(chunk.response); // 如果请求失败，释放内存
            chunk.response = NULL;
        }

        curl_easy_cleanup(curl); // 清理CURL资源
    }

    return chunk.response; // 返回响应内容，或者在失败时为NULL
}

/**
 * 发送HTTP POST请求。
 * @param url 请求的URL。
 * @param data 发送的数据。
 * @param data_size 发送数据的大小。
 * @param response_code 用于存储HTTP响应代码的变量的地址。
 * @param headers 自定义请求头。
 * @return 成功返回响应内容字符串，失败返回NULL。
 */
char *http_post(const char *url, const char *data, size_t data_size, long *response_code, struct curl_slist *headers)
{
    CURL *curl;
    CURLcode res;
    struct Memory chunk = {0};

    chunk.response = malloc(1);
    chunk.size = 0;

    curl = curl_easy_init();
    if (curl)
    {
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_POST, 1L);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data_size);
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);

        res = curl_easy_perform(curl);
        if (res != CURLE_OK)
        {
            fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
            free(chunk.response);
            chunk.response = NULL;
        }

        if (response_code)
        {
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, response_code);
        }

        curl_easy_cleanup(curl);
        curl_slist_free_all(headers);
    }

    return chunk.response;
}